package org.etk.orm.core;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.nodetype.NodeType;
import javax.jcr.nodetype.PropertyDefinition;
import org.etk.orm.api.DuplicateNameException;
import org.etk.orm.api.NameConflictResolution;
import org.etk.orm.api.NoSuchNodeException;
import org.etk.orm.api.Status;
import org.etk.orm.plugins.bean.mapping.NodeTypeKind;
import org.etk.orm.plugins.jcr.LinkType;
import org.etk.orm.plugins.jcr.SessionWrapper;
import org.etk.orm.plugins.jcr.type.MixinTypeInfo;
import org.etk.orm.plugins.jcr.type.PrimaryTypeInfo;
import org.etk.orm.plugins.mapper.ObjectMapper;
import static org.etk.orm.plugins.common.JCR.qualify;
public class DomainSessionImpl extends DomainSession {
/** . */
final Domain domain;
/** . */
private Map<String, EntityContext> contexts;
public DomainSessionImpl(Domain domain, SessionWrapper sessionWrapper) {
super(domain, sessionWrapper);
//
this.domain = domain;
this.contexts = new HashMap<String, EntityContext>();
}
protected void _setLocalName(EntityContext ctx, String localName) throws RepositoryException {
if (ctx == null) {
throw new NullPointerException();
}
//
switch (ctx.getStatus()) {
case TRANSIENT:
((TransientEntityContextState)ctx.state).setLocalName(localName);
break;
case PERSISTENT:
Node parentNode = ctx.getNode().getParent();
String name = ctx.getNode().getName();
int index = name.indexOf(':');
String prefix = index == -1 ? null : name.substring(0, index);
_move(ThrowableFactory.ISE, ctx, parentNode, prefix, localName);
break;
default:
throw new IllegalStateException("Removed node cannot have its name updated");
}
}
@Override
protected String _getLocalName(EntityContext ctx) throws RepositoryException {
if (ctx == null) {
throw new NullPointerException();
}
//
switch (ctx.getStatus()) {
default:
return ctx.state.getLocalName();
case PERSISTENT:
Node node = ctx.state.getNode();
Node parentNode = node.getParent();
String name = node.getName();
int index = name.indexOf(':');
String localName = index == -1 ? name : name.substring(index + 1);
return domain.decodeName(parentNode, localName, NameKind.OBJECT);
}
}
@Override
protected <E> E _findByPath(Class<E> clazz, String path) throws RepositoryException {
Node node = sessionWrapper.getNode(path);
if (node != null) {
return _findByNode(clazz, node);
}
return null;
}
protected <O> O _findByPath(EntityContext ctx, Class<O> clazz, String relPath) throws RepositoryException {
Node origin;
if (ctx != null) {
origin = ctx.state.getNode();
} else {
origin = _getRoot();
}
Node node = sessionWrapper.getNode(origin, relPath);
if (node != null) {
return _findByNode(clazz, node);
}
return null;
}
protected <T1 extends Throwable> void _persist(ThrowableFactory<T1> nullLocaleNameTF, EntityContext ctx, String prefix, String localName) throws T1, RepositoryException {
if (ctx == null) {
throw new NullPointerException("No null object context accepted");
}
if (localName == null) {
String msg = "No relative path specified";
throw nullLocaleNameTF.newThrowable(msg);
}
//
if (ctx.getStatus() != Status.TRANSIENT) {
String msg = "Attempt to persist non transient object " + ctx;
log.error(msg);
throw new IllegalArgumentException(msg);
}
//
log.trace("Setting context {} for insertion", ctx);
log.trace("Adding node for context {} and node type {}", ctx, ctx.mapper);
//
_persist(_getRoot(), prefix, localName, ctx);
}
protected <T1 extends Throwable, T2 extends Throwable, T3 extends Throwable> void _persist(
ThrowableFactory<T1> srcStateTF,
ThrowableFactory<T2> dstStateTF,
ThrowableFactory<T3> nullLocaleNameTF,
ObjectContext srcCtx,
String prefix,
String localName,
EntityContext dstCtx) throws
T1, T2, T3, NullPointerException, RepositoryException {
if (srcCtx == null) {
String msg = "Cannot insert context " + dstCtx + " as a child of a null context";
log.error(msg);
throw new NullPointerException(msg);
}
if (dstCtx.getStatus() != Status.TRANSIENT) {
String msg = "Attempt to insert non transient context " + dstCtx + " as child of " + srcCtx;
log.error(msg);
throw dstStateTF.newThrowable();
}
if (localName == null) {
String msg = "Attempt to insert context " + dstCtx + " with no name to " + srcCtx;
log.error(msg);
throw nullLocaleNameTF.newThrowable(msg);
}
if (srcCtx.getStatus() != Status.PERSISTENT) {
String msg = "Attempt to insert context " + dstCtx + " as child of non persistent context " + srcCtx;
log.error(msg);
throw srcStateTF.newThrowable(msg);
}
//
Node parentNode = srcCtx.getEntity().state.getNode();
//
_persist(parentNode, prefix, localName, dstCtx);
}
private void _persist(Node srcNode, String prefix, String localName, EntityContext dstCtx) throws RepositoryException {
ObjectMapper mapper = dstCtx.mapper;
//
localName = domain.encodeName(srcNode, localName, NameKind.OBJECT);
//
String name = qualify(prefix, localName);
//
NameConflictResolution onDuplicate = NameConflictResolution.FAIL;
NodeType parentNodeType = srcNode.getPrimaryNodeType();
ObjectMapper parentTypeMapper = domain.getTypeMapper(parentNodeType.getName());
if (parentTypeMapper != null) {
onDuplicate = parentTypeMapper.getOnDuplicate();
}
// Check insertion capability
// julien : that should likely instead use JCR failure for better performance
Node previousNode = sessionWrapper.getNode(srcNode, name);
if (previousNode != null) {
log.trace("Found existing child with same name {}", name);
if (onDuplicate == NameConflictResolution.FAIL) {
String msg = "Attempt to insert context " + dstCtx + " as an existing child with name " + name + " child of node " + srcNode.getPath();
log.error(msg);
throw new DuplicateNameException(msg);
} else {
log.trace("About to remove same name {} child with id {}", previousNode.getPath(), previousNode.getName());
remove(previousNode);
}
}
//
String primaryNodeTypeName = mapper.getNodeTypeName();
log.trace("Setting context {} for insertion", dstCtx);
log.trace("Adding node for context {} and node type {} as child of node {}", dstCtx, primaryNodeTypeName, srcNode.getPath());
//
Node dstNode = sessionWrapper.addNode(srcNode, name, primaryNodeTypeName, Collections.<String>emptyList());
// If the node is not referenceable, make it so
if (!domain.nodeInfoManager.isReferenceable(dstNode)) {
dstNode.addMixin("mix:referenceable");
}
//
nodeAdded(dstNode, dstCtx);
//
log.trace("Added context {} for path {}", dstCtx, dstCtx.getId(), dstNode.getPath());
}
@Override
protected EntityContext _copy(EntityContext srcCtx, String prefix, String localName) throws RepositoryException {
return _copy(getRoot(), srcCtx, qualify(prefix, localName));
}
@Override
protected EntityContext _copy(EntityContext parentCtx, EntityContext srcCtx, String prefix, String localName) throws RepositoryException {
if (parentCtx == null) {
throw new NullPointerException();
}
if (parentCtx.getStatus() == Status.PERSISTENT) {
throw new IllegalArgumentException("Parent object is not persistent");
}
return _copy(parentCtx.getNode(), srcCtx, qualify(prefix, localName));
}
private EntityContext _copy(Node parentNode, EntityContext srcCtx, String name) throws RepositoryException {
if (srcCtx == null) {
throw new NullPointerException();
}
if (name == null) {
throw new NullPointerException();
}
if (srcCtx.getStatus() != Status.PERSISTENT) {
throw new IllegalArgumentException("Copied object is not persistent");
}
//
EntityContext dstCtx = (EntityContext)_create(srcCtx.mapper.getObjectClass(), null);
//
String prefix;
String localName;
int index = name.indexOf(':');
if (index == -1) {
prefix = null;
localName = name;
} else {
prefix = name.substring(0, index);
localName = name.substring(index + 1);
}
//
_persist(parentNode, prefix, localName, dstCtx);
//
Node dstNode = dstCtx.getNode();
// Copy mixins
for (NodeType mixinNodeType : srcCtx.getNode().getMixinNodeTypes()) {
dstNode.addMixin(mixinNodeType.getName());
}
// Copy node state
for (Iterator<Property> i = sessionWrapper.getProperties(srcCtx.getNode());i.hasNext();) {
Property p = i.next();
PropertyDefinition def = p.getDefinition();
if (def.isProtected()) {
// We skip protected state
} else {
if (def.isMultiple()) {
Value[] values = p.getValues();
dstNode.setProperty(p.getName(), values);
} else {
Value value = p.getValue();
dstNode.setProperty(p.getName(), value);
}
}
}
// Copy children
for (Iterator<Node> i = sessionWrapper.getChildren(srcCtx.getNode());i.hasNext();) {
Node n = i.next();
EntityContext c = _getEntity(n);
if (c == null) {
throw new UnsupportedOperationException();
} else {
_copy(dstNode, c, n.getName());
}
}
//
return dstCtx;
}
@Override
protected void _addMixin(EntityContext entityCtx, EmbeddedContext mixinCtx) throws RepositoryException {
if (entityCtx == null) {
throw new NullPointerException();
}
if (mixinCtx == null) {
throw new NullPointerException();
}
// Maybe they are already wired
if (mixinCtx.relatedEntity != null) {
if (mixinCtx.relatedEntity != entityCtx) {
throw new IllegalArgumentException();
}
} else {
EmbeddedContext previousMixinCtx = (EmbeddedContext)entityCtx.getAttribute(mixinCtx.mapper);
if (previousMixinCtx != null) {
if (previousMixinCtx != mixinCtx) {
throw new IllegalStateException();
}
} else {
//
String mixinTypeName = mixinCtx.mapper.getNodeTypeName();
Node node = entityCtx.state.getNode();
//
if (!sessionWrapper.canAddMixin(node, mixinTypeName)) {
throw new IllegalArgumentException("Cannot add mixin " + mixinCtx + " to context " + entityCtx);
}
// Add mixin
sessionWrapper.addMixin(node, mixinTypeName);
//
NodeType mixinType = sessionWrapper.getNodeType(mixinTypeName);
MixinTypeInfo mixinTypeInfo = domain.nodeInfoManager.getMixinTypeInfo(mixinType);
// Perform wiring
entityCtx.setAttribute(mixinCtx.mapper, mixinCtx);
mixinCtx.relatedEntity = entityCtx;
mixinCtx.typeInfo = mixinTypeInfo;
}
}
}
@Override
protected EmbeddedContext _getEmbedded(EntityContext entityCtx, Class<?> embeddedClass) throws RepositoryException {
if (entityCtx == null) {
throw new NullPointerException();
}
if (embeddedClass == null) {
throw new NullPointerException();
}
// That's a necessary evil
ObjectMapper<EmbeddedContext> mapper = (ObjectMapper<EmbeddedContext>)domain.getTypeMapper(embeddedClass);
//
EmbeddedContext embeddedCtx = null;
if (mapper != null) {
embeddedCtx = (EmbeddedContext)entityCtx.getAttribute(mapper);
//
if (embeddedCtx == null) {
Node node = entityCtx.state.getNode();
if (mapper.getKind() == NodeTypeKind.MIXIN) {
String mixinTypeName = mapper.getNodeTypeName();
if (sessionWrapper.haxMixin(node, mixinTypeName)) {
NodeType mixinType = sessionWrapper.getNodeType(mixinTypeName);
MixinTypeInfo mixinTypeInfo = domain.nodeInfoManager.getMixinTypeInfo(mixinType);
//
embeddedCtx = new EmbeddedContext(mapper, this);
entityCtx.setAttribute(embeddedCtx.mapper, embeddedCtx);
embeddedCtx.relatedEntity = entityCtx;
embeddedCtx.typeInfo = mixinTypeInfo;
}
} else {
PrimaryTypeInfo typeInfo = entityCtx.state.getTypeInfo();
PrimaryTypeInfo superTI = (PrimaryTypeInfo)typeInfo.getSuperType(mapper.getNodeTypeName());
if (superTI != null) {
embeddedCtx = new EmbeddedContext(mapper, this);
entityCtx.setAttribute(embeddedCtx.mapper, embeddedCtx);
embeddedCtx.relatedEntity = entityCtx;
embeddedCtx.typeInfo = superTI;
}
}
}
}
//
return embeddedCtx;
}
@Override
protected <T1 extends Throwable, T2 extends Throwable> void _move(
ThrowableFactory<T1> srcStateTF,
ThrowableFactory<T2> dstStateTF,
EntityContext srcCtx,
ObjectContext dstCtx,
String dstPrefix,
String dstLocalName) throws
T1, T2, NullPointerException, RepositoryException {
if (dstCtx == null) {
String msg = "Cannot move to null context";
log.error(msg);
throw new NullPointerException(msg);
}
if (dstCtx.getStatus() != Status.PERSISTENT) {
String msg = "Attempt to move child " + srcCtx + " to a non persistent context " + dstCtx;
log.error(msg);
throw dstStateTF.newThrowable(msg);
}
//
Node dstNode = dstCtx.getEntity().state.getNode();
//
_move(srcStateTF, srcCtx, dstNode, dstPrefix, dstLocalName);
}
private <T1 extends Throwable> void _move(
ThrowableFactory<T1> srcStateTF,
EntityContext srcCtx,
Node dstNode,
String dstPrefix,
String dstLocalName) throws T1, NullPointerException, RepositoryException {
if (srcCtx == null) {
String msg = "Cannot move null context";
log.error(msg);
throw new NullPointerException(msg);
}
if (srcCtx.getStatus() != Status.PERSISTENT) {
String msg = "Attempt to move non persistent context " + srcCtx + " as child of " + dstNode.getPath();
log.error(msg);
throw srcStateTF.newThrowable(msg);
}
//
dstLocalName = domain.encodeName(dstNode, dstLocalName, NameKind.OBJECT);
//
String dstName = qualify(dstPrefix, dstLocalName);
//
Node srcNode = srcCtx.state.getNode();
//
NameConflictResolution onDuplicate = NameConflictResolution.FAIL;
NodeType parentNodeType = dstNode.getPrimaryNodeType();
ObjectMapper parentTypeMapper = domain.getTypeMapper(parentNodeType.getName());
if (parentTypeMapper != null) {
onDuplicate = parentTypeMapper.getOnDuplicate();
}
// Check insertion capability
Node previousNode = sessionWrapper.getNode(dstNode, dstName);
if (previousNode != null) {
log.trace("Found existing child with same name {}", dstName);
if (srcNode.getParent() == dstNode) {
// We do nothing as it's a noop
} else {
if (onDuplicate == NameConflictResolution.FAIL) {
String msg = "Attempt to move context " + dstNode.getPath() + " as an existing child with name " + dstName + " child of node " + dstNode.getPath();
log.error(msg);
throw new DuplicateNameException(msg);
} else {
log.trace("About to remove same name {} child with id {}", previousNode.getPath(), previousNode.getName());
//previousNode.remove();
throw new UnsupportedOperationException("Do that properly");
}
}
} else {
sessionWrapper.move(srcNode, dstNode, dstName);
}
// Generate some kind of event ????
}
protected void _orderBefore(ObjectContext parentCtx, EntityContext srcCtx, EntityContext dstCtx) throws RepositoryException {
if (parentCtx == null) {
throw new NullPointerException();
}
if (srcCtx == null) {
throw new NullPointerException();
}
//
Node parentNode = parentCtx.getEntity().state.getNode();
Node srcNode = srcCtx.state.getNode();
Node dstNode = dstCtx != null ? dstCtx.state.getNode() : null;
//
sessionWrapper.orderBefore(parentNode, srcNode, dstNode);
}
protected ObjectContext _create(Class<?> clazz, String localName) throws NullPointerException, IllegalArgumentException, RepositoryException {
if (clazz == null) {
throw new NullPointerException();
}
//
ObjectMapper<?> typeMapper = domain.getTypeMapper(clazz);
if (typeMapper == null) {
throw new IllegalArgumentException("The type " + clazz.getName() + " is not mapped");
}
//
if (typeMapper.getKind() == NodeTypeKind.PRIMARY && typeMapper.isAbstract()) {
throw new IllegalArgumentException("The type " + clazz.getName() + " is abstract");
}
//
TransientEntityContextState state = new TransientEntityContextState(this);
//
ObjectContext octx;
if (typeMapper.getKind() == NodeTypeKind.PRIMARY) {
EntityContext ctx = new EntityContext((ObjectMapper<EntityContext>)typeMapper, state);
//
if (localName != null) {
ctx.setLocalName(localName);
}
//
broadcaster.created(ctx.getObject());
//
octx = ctx;
} else {
if (localName != null) {
throw new IllegalArgumentException("Cannot create a mixin type with a name");
}
octx = new EmbeddedContext((ObjectMapper<EmbeddedContext>)typeMapper, this);
}
return octx;
}
protected <O> O _findById(Class<O> clazz, String id) throws RepositoryException {
if (clazz == null) {
throw new NullPointerException();
}
if (id == null) {
throw new NullPointerException();
}
// Attempt to load the object
log.trace("About to load node with id {} and class {}", id, clazz.getName());
Node node = sessionWrapper.getNodeByUUID(id);
if (node != null) {
return _findByNode(clazz, node);
} else {
log.trace("Could not find node with id {}", id, clazz.getName());
}
return null;
}
protected <O> O _findByNode(Class<O> clazz, Node node) throws RepositoryException {
if (clazz == null) {
throw new NullPointerException();
}
//
EntityContext ctx = _getEntity(node);
//
if (ctx == null) {
return null;
} else {
return cast(ctx, clazz);
}
}
protected EntityContext _getEntity(Node node) throws RepositoryException {
if (node == null) {
throw new NullPointerException();
}
//
if (!domain.nodeInfoManager.isReferenceable(node)) {
log.trace("Cannot map non referenceable node {} to a chromattic object", node.getPath());
return null;
}
// Attempt to get the object
return nodeRead(node);
}
protected void _save() throws RepositoryException {
sessionWrapper.save();
}
protected void _remove(EntityContext context) throws RepositoryException {
if (context == null) {
throw new NullPointerException();
}
switch (context.state.getStatus()) {
case TRANSIENT:
throw new IllegalStateException("Cannot remove transient node");
case PERSISTENT:
Node node = context.state.getNode();
remove(node);
break;
case REMOVED:
throw new IllegalStateException("Cannot remove removed node");
default:
throw new AssertionError();
}
}
private static class Removed {
private final String id;
private final String path;
private final String localName;
private final EntityContext ctx;
private Removed(String id, String path, String localName, EntityContext ctx) {
this.id = id;
this.path = path;
this.localName = localName;
this.ctx = ctx;
}
}
private void remove(Node node) throws RepositoryException {
List<Removed> removeds = new LinkedList<Removed>();
String pathToRemove = node.getPath();
for (Map.Entry<String, EntityContext> ctxEntry : contexts.entrySet()) {
EntityContext ctx = ctxEntry.getValue();
Node ctxNode = ctx.state.getNode();
if (ctxNode.getPath().startsWith(pathToRemove)) {
removeds.add(new Removed(ctx.getId(), ctx.getPath(), ctx.getLocalName(), ctx));
}
}
// Perform removal
sessionWrapper.remove(node);
//
Collection<EntityContext> ctxs = contexts.values();
//
for (Removed removed : removeds) {
String path = removed.path;
log.trace("Removing context for path {}", path);
removed.ctx.state = new RemovedEntityContextState(this, path, removed.localName, removed.ctx.getTypeInfo());
ctxs.remove(removed.ctx);
broadcaster.removed(removed.id, removed.path, removed.localName, removed.ctx.getObject());
log.trace("Removed context {} for path {}", removed.ctx, path);
}
}
protected EntityContext _getReferenced(ObjectContext referentCtx, String name, LinkType linkType) throws RepositoryException {
if (referentCtx.getStatus() != Status.PERSISTENT) {
throw new IllegalStateException();
}
Node referent = referentCtx.getEntity().state.getNode();
Node referenced = sessionWrapper.getReferenced(referent, name, linkType);
if (referenced != null) {
return _getEntity(referenced);
} else {
return null;
}
}
protected boolean _setReferenced(ObjectContext referentCtx, String name, EntityContext referencedCtx, LinkType linkType) throws RepositoryException {
if (referentCtx.getStatus() != Status.PERSISTENT) {
throw new IllegalStateException("Cannot create a relationship with a non persisted context " + this);
}
//
Node referent = referentCtx.getEntity().state.getNode();
// Then create
if (referencedCtx != null) {
if (referencedCtx.getStatus() != Status.PERSISTENT) {
throw new IllegalStateException();
}
// Should do some type checking probably!!!!
//
Node referenced = referencedCtx.state.getNode();
//
Node previouslyReferenced = sessionWrapper.setReferenced(referent, name, referenced, linkType);
// OK the nodes are referenceable, they always have an UUID
if (previouslyReferenced != null) {
String previousReferencedId = previouslyReferenced.getUUID();
String referencedId = referenced.getUUID();
return !referencedId.equals(previousReferencedId);
} else {
return true;
}
} else {
return null != sessionWrapper.setReferenced(referent, name, null, linkType);
}
}
protected <T> Iterator<T> _getReferents(EntityContext referencedCtx, String name, Class<T> filterClass, LinkType linkType) throws RepositoryException {
Node referenced = referencedCtx.getEntity().state.getNode();
Iterator<Node> referents = sessionWrapper.getReferents(referenced, name, linkType);
return new ReferentCollectionIterator<T>(this, referents, filterClass, name);
}
protected void _removeChild(ObjectContext ctx, String prefix, String localName) throws RepositoryException {
localName = domain.encodeName(ctx, localName, NameKind.OBJECT);
String name = qualify(prefix, localName);
Node node = ctx.getEntity().state.getNode();
Node childNode = sessionWrapper.getNode(node, name);
if (childNode != null) {
remove(childNode);
}
}
protected EntityContext _getChild(ObjectContext ctx, String prefix, String localName) throws RepositoryException {
localName = domain.encodeName(ctx, localName, NameKind.OBJECT);
String name = qualify(prefix, localName);
Node node = ctx.getEntity().state.getNode();
log.trace("About to load the name child {} of context {}", name, this);
Node child = sessionWrapper.getChild(node, name);
if (child != null) {
log.trace("Loaded named child {} of context {} with path {}", name, this, child.getPath());
return _getEntity(child);
} else {
log.trace("No child named {} to load for context {}", name, this);
return null;
}
}
protected <T> Iterator<T> _getChildren(ObjectContext ctx, Class<T> filterClass) throws RepositoryException {
Node node = ctx.getEntity().state.getNode();
Iterator<Node> iterator = sessionWrapper.getChildren(node);
return new ChildCollectionIterator<T>(this, iterator, filterClass);
}
protected EntityContext _getParent(EntityContext ctx) throws RepositoryException {
if (ctx.getStatus() != Status.PERSISTENT) {
throw new IllegalStateException();
}
Node node = ctx.state.getNode();
Node parent = sessionWrapper.getParent(node);
return _getEntity(parent);
}
protected Node _getRoot() throws RepositoryException {
Session session = sessionWrapper.getSession();
List<String> pathSegments = domain.rootNodePathSegments;
Node current = session.getRootNode();
String rootNodeType = domain.rootNodeType;
boolean created = false;
if (!pathSegments.isEmpty()) {
// We use that kind of loop to avoid object creation
for (int i = 0;i < pathSegments.size();i++) {
String pathSegment = pathSegments.get(i);
if (current.hasNode(pathSegment)) {
current = current.getNode(pathSegment);
} else {
if (domain.rootCreateMode == Domain.NO_CREATE_MODE) {
throw new NoSuchNodeException("No existing root node " + domain.rootNodePath);
} else {
if (rootNodeType != null) {
current = current.addNode(pathSegment, rootNodeType);
} else {
current = current.addNode(pathSegment);
}
created = true;
}
}
}
}
if (created) {
if (domain.rootCreateMode == Domain.CREATE_MODE) {
// Find first persistent ancestor
Node toSave = current;
while (toSave.isNew()) {
toSave = toSave.getParent();
}
// And save it
toSave.save();
}
}
return current;
}
private <O> O cast(EntityContext ctx, Class<O> clazz) {
Object object = ctx.object;
if (clazz.isInstance(object)) {
return clazz.cast(object);
} else {
String msg = "Could not cast context " + ctx + " with class " + object.getClass().getName() + " to class " + clazz.getName();
throw new ClassCastException(msg);
}
}
/**
* <p>Read the node and returns a related entity context.</p>
*
* </p>When the node is mapped to a chromattic type the following occurs:
* <ul>
* <li>any entity context already present in the current session is returned</li>
* <li>otherwise an entity context is created from the related chromattic type and is inserted in the session</li>
* <li>a load event is broadcasted to listeners</li>
* </ul>
* The node must have the mixin mix:referenceable otherwise a repositoty exception will be thrown.</p>
*
* <p>When the node is not mapped, null is returned.</p>
*
* @param node the node to read
* @return the corresponding entity context
* @throws RepositoryException any repository exception
*/
private EntityContext nodeRead(Node node) throws RepositoryException {
NodeType nodeType = node.getPrimaryNodeType();
String nodeTypeName = nodeType.getName();
ObjectMapper mapper = domain.getTypeMapper(nodeTypeName);
if (mapper != null) {
EntityContext ctx = contexts.get(node.getUUID());
if (ctx == null) {
ctx = new EntityContext((ObjectMapper<EntityContext>)mapper, new PersistentEntityContextState(node, this));
log.trace("Inserted context {} loaded from node path {}", ctx, node.getPath());
contexts.put(node.getUUID(), ctx);
broadcaster.loaded(ctx, ctx.getObject());
}
else {
log.trace("Context {} is already present for path ", ctx, node.getPath());
}
return ctx;
}
else {
log.trace("Could not find mapper for node type {}", nodeTypeName);
return null;
}
}
private void nodeAdded(Node node, EntityContext ctx) throws RepositoryException {
NodeType nodeType = node.getPrimaryNodeType();
String nodeTypeName = nodeType.getName();
ObjectMapper mapper = domain.getTypeMapper(nodeTypeName);
if (mapper != null) {
if (contexts.containsKey(node.getUUID())) {
String msg = "Attempt to replace an existing context " + ctx + " with path " + node.getPath();
log.error(msg);
throw new AssertionError(msg);
}
log.trace("Inserted context {} for path {}", ctx, node.getPath());
contexts.put(node.getUUID(), ctx);
ctx.state = new PersistentEntityContextState(node, this);
broadcaster.added(ctx, ctx.getObject());
}
else {
log.trace("Could not find mapper for node type {}", nodeTypeName);
}
}
public void _close() {
sessionWrapper.close();
}
}